	#include "vxmousetransmitter.h"
#include "vx.h"


VxMouseTransmitter::VxMouseTransmitter() :
		QObject::QObject(),
		_pressed(false)
{
	_buildStateMachine();

	qApp->installEventFilter(this);
}


bool VxMouseTransmitter::eventFilter(QObject * obj, QEvent * event)
{

	if (!_pressed && event->type() == QEvent::MouseButtonPress){
		_pressed = true;
		_event = static_cast<QMouseEvent *>(event);
		_sender = obj;
		_mouseTrack.clear();
		_momentumt.restart();
		emit mousePressed(_event);
	} else

	if (event->type() == QEvent::MouseButtonRelease){
		_pressed = false;
		_event = static_cast<QMouseEvent *>(event);
		_movedPos = _event->globalPos();

		_checkMomentum();
		emit mouseReleased(_event);
	} else

	if (_pressed && event->type() == QEvent::MouseMove){
		_event = static_cast<QMouseEvent *>(event);
		_movedPos = _event->globalPos();

		MouseTrackPoint mtpoint;
		mtpoint.point = _movedPos;
		mtpoint.time = _momentumt.elapsed();
		_mouseTrack.push_back(mtpoint);
		emit mousePressedMove(_movedPos);
	} else

	if (!_pressed && event->type() == QEvent::MouseMove){
		_event = static_cast<QMouseEvent *>(event);
		_globalPos = _event->globalPos();
		_movedPos = _event->globalPos();
		emit mouseReleasedMove(_globalPos);
	}

	return QObject::eventFilter(obj, event);
}


VxMouseTransmitter * VxMouseTransmitter::_instance = 0;


VxMouseTransmitter * VxMouseTransmitter::instance()
{
	if (_instance == 0){
		_instance = new VxMouseTransmitter();
	}

	return _instance;
}



void VxMouseTransmitter::_buildStateMachine()
{
	QStateMachine * machine = new QStateMachine();

	QState * stateMouseReleased = new QState(machine);
	QState * stateMousePressed = new QState(machine);
	QState * stateMousePressedIdle = new QState(machine);

	//
	// released -> pressed
	//

	QSignalTransition * trnsnReleasedToPressed =
			new QSignalTransition(this, SIGNAL(mousePressed(QMouseEvent*)));

	trnsnReleasedToPressed->setTargetState(stateMousePressed);

	stateMouseReleased->addTransition(trnsnReleasedToPressed);

	//
	// released	 <-	pressed
	//

	QSignalTransition * trnsnPressedToReleasedByMove =
			new QSignalTransition(this, SIGNAL(mousePressedMove(QPoint)));

	QSignalTransition * trnsnPressedToReleasedByReleased =
			new QSignalTransition(this, SIGNAL(mouseReleased(QMouseEvent*)));

	trnsnPressedToReleasedByMove->setTargetState(stateMouseReleased);
	trnsnPressedToReleasedByReleased->setTargetState(stateMouseReleased);

	stateMousePressed->addTransition(trnsnPressedToReleasedByMove);
	stateMousePressed->addTransition(trnsnPressedToReleasedByReleased);

	//
	//				pressed ->	idle1
	//

	QTimer * timerPressedIdle = new QTimer();
	timerPressedIdle->setInterval(Vx::PressedIdle);
	timerPressedIdle->setSingleShot(true);

	connect(stateMousePressed, SIGNAL(entered()), timerPressedIdle, SLOT(start()));
	connect(stateMouseReleased, SIGNAL(entered()), timerPressedIdle, SLOT(stop()));

	QSignalTransition * trnsnPressedToIdle =
			new QSignalTransition(timerPressedIdle, SIGNAL(timeout()));

	trnsnPressedToIdle->setTargetState(stateMousePressedIdle);
	stateMousePressed->addTransition(trnsnPressedToIdle);

	//
	//	released			<-	idle1
	//

	QSignalTransition * trnsnIdle1ToReleasedByMove =
			new QSignalTransition(this, SIGNAL(mousePressedMove(QPoint)));

	QSignalTransition * trnsnIdle1ToReleasedByReleased =
			new QSignalTransition(this, SIGNAL(mouseReleased(QMouseEvent*)));

	trnsnIdle1ToReleasedByMove->setTargetState(stateMouseReleased);
	trnsnIdle1ToReleasedByReleased->setTargetState(stateMouseReleased);

	stateMousePressedIdle->addTransition(trnsnIdle1ToReleasedByMove);
	stateMousePressedIdle->addTransition(trnsnIdle1ToReleasedByReleased);

	//
	//
	//
	connect(stateMousePressedIdle, SIGNAL(entered()), this, SIGNAL(mousePressedIdle()));

	//
	// Mouse Released Move Signal
	//

	QTimer * timerReleasedIdle = new QTimer();
	timerReleasedIdle->setInterval(Vx::ReleasedIdle);
	timerReleasedIdle->setSingleShot(false);

	connect(this, SIGNAL(mouseReleasedMove(QPoint)), timerReleasedIdle, SLOT(start()));
	connect(stateMousePressed, SIGNAL(entered()), timerReleasedIdle, SLOT(stop()));

	machine->setInitialState(stateMouseReleased);
	machine->start();

	connect(timerReleasedIdle, SIGNAL(timeout()), this, SLOT(_mouseReleasedMove()));
	//connect(timerReleasedIdle, SIGNAL(timeout()), timerReleasedIdle, SLOT(stop()));

}

void VxMouseTransmitter::_mouseReleasedMove()
{
	emit mouseReleasedIdle(_globalPos);
}

void VxMouseTransmitter::_checkMomentum()
{
	int n = _mouseTrack.count();

	if (n < Vx::MouseMomentumCnt+1){
		return;
	}

	MouseTrackPoint f0 = _mouseTrack.at(n - Vx::MouseMomentumCnt);
	MouseTrackPoint f1 = _mouseTrack.last();

	QPoint dltp = f1.point - f0.point;
	qreal dlt = dltp.manhattanLength();
	qreal dtm = f1.time - f0.time;

	qreal momentum = dlt/dtm;
	if (momentum < Vx::MouseMomentumDlt/10){
		return;
	}
	emit mouseMomentum(dltp, momentum);

}

bool VxMouseTransmitter::pressed()
{
	return _pressed;
}

